﻿using Foxit.PDF;
using Foxit.PDF.PageElements;
using Sustainalytics.Entities;
using Sustainalytics.Entities.Governance;
using Sustainalytics.Reporting.Framework;
using Sustainalytics.RiskRatings.Reporting;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sustainalytics.Governance.Reporting
{
    public class IndicatorSection : PdfReportSectionGenerator
    {
        private float CurrentYOffset { get; set; }
        private PdfReportPage CurrentPage { get; set; }
        public override void ComposeSectionContent()
        {
            _report.PageSize = PageSize.A4;
            _report.PageOrientation = PageOrientation.Portrait;
            _report.PageMargins = 25f;
            _report.PageDimensions = new PageDimensions(_report.PageSize, _report.PageOrientation, _report.PageMargins);

            if (!_dataSource.Issues.Any()) return;

            var outlinePosition = new OutlinePosition
            {
                Name = "Issues",
                PageNumber = 1,
                ChildOutlinePositions = new List<OutlinePosition>()
            };

            _outlinePositions.Add(outlinePosition);
            
            foreach (var issue in _dataSource.Issues.OrderBy(i => i.Number))
            {
                GovernanceIssuePerformance issuePerformance = null;

                if (_dataSource.IssuesPerformance != null)
                {
                    issuePerformance = _dataSource.IssuesPerformance.SingleOrDefault(ip => ip.Number == issue.Number);
                }

                if (issue.Indicators.Any())
                {
                    CurrentPage = _report.NewPage();
                    _report.Pages.Add(CurrentPage);

                    var pageNumber = _report.Pages.Count;

                    var childOutlinePosition = new OutlinePosition
                    {
                        Id = issue.Id,
                        Name = issue.Name,
                        PageNumber = pageNumber,
                        VerticalPosition = 0.0f,
                        ChildOutlinePositions = new List<OutlinePosition>()
                    };

                    outlinePosition.ChildOutlinePositions.Add(childOutlinePosition);

                    var table = AddIssueTable(issue, issuePerformance);
                    CurrentPage.Elements.Add(table);

                    CurrentYOffset = 165f;
                    var issueIndicators = issue.Indicators.OrderBy(i => Convert.ToInt32(i.Number.Substring(5))).ToList();
                    var nrIndicator = 1;
                    foreach (var indicator in issueIndicators)
                    {
                        if (CurrentYOffset > _report.PageDimensions.Body.Height-100f)
                        {
                            CurrentYOffset = 15f;
                            CurrentPage = _report.NewPage();
                            _report.Pages.Add(CurrentPage);
                        }
                        var currentYOffset = AddIndicatorHeader(CurrentPage, indicator, 125f, CurrentYOffset, nrIndicator);
                        CurrentYOffset = AddIndicatorDetails(CurrentPage, indicator, 85f, currentYOffset);
                        nrIndicator++;
                    }
                }

            }
        }

        private float AddIndicatorHeader(PdfReportPage page, GovernanceIndicator indicator, float x, float currentYOffset, int nrIndicator)
        {
            const float fontSize = 11f;
            const float numberFontSize = 8f;
            var width = _report.PageMaxWidth;
            if (nrIndicator != 1)
            {
                page.AddElement(new Line(0.0f, currentYOffset, width, currentYOffset, 0.5f, RgbColor.Black));
                currentYOffset += 5f;
            }
            page.Elements.Add(new Label(indicator.Name, 0f, currentYOffset, 250f, fontSize+2f, Fonts.MontserratRegular, fontSize, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Label(indicator.Number, _report.PageMaxWidth-30f, currentYOffset+5f, 100f, numberFontSize+2f, Fonts.CalibriRegular, numberFontSize, TextAlign.Left, RgbColor.Black));
            currentYOffset += 30;

            return currentYOffset;
        }

        private float AddIndicatorDetails(PdfReportPage page,GovernanceIndicator indicator, float x, float currentYOffset)
        {
            const float fontSize = 24f;
            const float radius = 18f;
            var width = _report.PageMaxWidth;
            float top = currentYOffset;

            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 8.5f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };

            page.Elements.Add(new BulletScore
            {
                Top = top,
                Left = 0.0f,
                Radius = radius,
                Value = indicator.Score.ToString(),
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = fontSize
            });

            var description = string.Empty;
            var newWidth = width - 85f;
            
            if (!string.IsNullOrEmpty(indicator.Description))
            {
                description = indicator.Description;

                var formattedTextArea = new FormattedTextArea(description, x, currentYOffset, newWidth, 200f, style);
                var textAreaHeight = formattedTextArea.GetRequiredHeight();

                formattedTextArea = new FormattedTextArea(description, x, currentYOffset, newWidth, textAreaHeight, style);

                page.Elements.Add(formattedTextArea);
                currentYOffset += textAreaHeight + 10f;
            }

            if (indicator.Tickedboxes != null && indicator.Tickedboxes.Any())
            {
                foreach (var tickedbox in indicator.Tickedboxes)
                {
                    var text = string.Format("<p>• {0}</p>", tickedbox.Value);
                    var formattedTextArea = new FormattedTextArea(text, x, currentYOffset, width, 25f, style);
                    var textAreaHeight = formattedTextArea.GetRequiredHeight();
                    formattedTextArea = new FormattedTextArea(text, x, currentYOffset, width, textAreaHeight, style);
                    page.Elements.Add(formattedTextArea);
                    currentYOffset += textAreaHeight + 3f;
                }
                
            }
            if (!string.IsNullOrWhiteSpace(indicator.Comment))
            {

                var comment = indicator.Comment
                    .Replace("<div>", "<p>")
                    .Replace("</div>", "</p>")
                    .Replace("<div />", "</p>")
                    .Replace("<br />", "</p><p>");
                comment = $"<p>Note: {HTMLConvertor.ConvertComment(comment)}</p>";
                var remainingComment = string.Empty;
                if (comment.Length > 7500)
                {
                    var splitedComment = comment.Substring(0, 7500);
                    remainingComment = comment.Substring(7450);
                    comment = splitedComment;
                }
                
                var formattedTextArea = new FormattedTextArea(comment, x, currentYOffset, newWidth, 300f, style);
                var textAreaHeight = formattedTextArea.GetRequiredHeight();
                if (currentYOffset + textAreaHeight > (_report.PageDimensions.Body.Height - 150f))
                {
                    currentYOffset = 15f;
                    CurrentPage = _report.NewPage();
                    _report.Pages.Add(CurrentPage);
                    formattedTextArea = new FormattedTextArea(comment, x, currentYOffset, newWidth, textAreaHeight, style);
                    CurrentPage.AddElement(formattedTextArea);
                }
                else
                {
                    formattedTextArea = new FormattedTextArea(comment, x, currentYOffset, newWidth, textAreaHeight, style);
                    page.AddElement(formattedTextArea);
                }
                if (!String.IsNullOrEmpty(remainingComment))
                {
                    formattedTextArea = new FormattedTextArea(remainingComment, x, currentYOffset, newWidth, 300f, style);
                    textAreaHeight = formattedTextArea.GetRequiredHeight();
                    currentYOffset = 15f;
                    CurrentPage = _report.NewPage();
                    _report.Pages.Add(CurrentPage);
                    formattedTextArea = new FormattedTextArea(remainingComment, x, currentYOffset, newWidth, textAreaHeight, style);
                    CurrentPage.AddElement(formattedTextArea);
                }

                currentYOffset += textAreaHeight;
            }
            else
            {
                currentYOffset += 15f;
            }

            return currentYOffset;
        }


        private Table AddIssueBullets(string issueName, string score, string assessment, string weight, int regionRank, int regionCount, int regionPercentile, float width)
        {
            const float fontSize = 24f;
            const float radius = 18f;
            const float valueFontSize = 10f;

            const float top = 10f;
            const float topOffset = 15f;
            const float rowHeight = 65f;
            const float height = rowHeight * 3;

            var bulletWidth = width * 0.07f;
            var textWidth = width * 0.19f;

            var table = GetDefaultTable(0.0f, 0.0f, width, height);
            table.CellDefault.VAlign = VAlign.Center;

            table.Columns.Add(bulletWidth);
            table.Columns.Add(textWidth);
            table.Columns.Add(bulletWidth);
            table.Columns.Add(textWidth);
            table.Columns.Add(bulletWidth);
            table.Columns.Add(textWidth);
            table.Columns.Add(bulletWidth);
            table.Columns.Add(80f);

            var row = table.Rows.Add(rowHeight);

            row.Cells.Add(new BulletScore
            {
                Top = top,
                Left = 0.0f,
                Radius = radius,
                Value = score,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = fontSize
            });

            var group = new Foxit.PDF.PageElements.Group();
            var text = string.Format("<p><b>{0}</b></p><p><b>Score</b></p>", issueName);
            var formattedTextArea = new FormattedTextArea(text, 0.0f, top, textWidth, rowHeight,
                Fonts.CalibriFontFamily, valueFontSize, false);
            var textRequiredHeight = formattedTextArea.GetRequiredHeight();
            group.Add(formattedTextArea);
            group.Add(
                new Line(0.0f, top + textRequiredHeight + 4f, 90f, top + textRequiredHeight + 4f, 0.5f, RgbColor.Black));
            group.Add(
                new Label(assessment, 0.0f, top + textRequiredHeight + 6f, 80f, 10f, Fonts.CalibriLight, 8f, TextAlign.Left, RgbColor.Black));

            row.Cells.Add(group);

            row.Cells.Add(new BulletScore
            {
                Top = top,
                Left = 0.0f,
                Radius = radius,
                Value = weight,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = fontSize - 8
            });

            text = string.Format("<p><b>{0}</b></p><p><b>Weight</b></p>", issueName);
            formattedTextArea = new FormattedTextArea(text, 0.0f, topOffset, textWidth, rowHeight,
                Fonts.CalibriFontFamily, valueFontSize, false);
            row.Cells.Add(formattedTextArea);

            row.Cells.Add(new RelativePositionBullet
            {
                Top = top,
                Left = 0.0f,
                Radius = radius,
                Rank = regionRank,
                Count = regionCount,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = 12f
            });

            text = "<p><b>Relative</b></p><p><b>Position</b></p>";
            formattedTextArea = new FormattedTextArea(text, 0.0f, topOffset, textWidth, rowHeight,
                Fonts.CalibriFontFamily, valueFontSize, false);
            row.Cells.Add(formattedTextArea);

            row.Cells.Add(new PercentileBullet
            {
                Top = top,
                Left = 0.0f,
                Radius = radius,
                Value = regionPercentile,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = fontSize
            });

            text = "<p><b>Percentile</b></p>";
            formattedTextArea = new FormattedTextArea(text, 0.0f, 5f + topOffset, 80f, rowHeight,
                Fonts.CalibriFontFamily, valueFontSize, false);
            row.Cells.Add(formattedTextArea);

            var requiredHeight = table.GetRequiredHeight();
            table.Height = requiredHeight;

            return table;
        }



        private Table AddIssueTable(GovernanceIssue issue, GovernanceIssuePerformance issuePerformance)
         {
            const float issueFontSize = 16f;
            const float issueTitleHeight = 22f;

            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 9f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };

            var score = string.Empty;
            var assesment = AssessmentType.Average_Performer.GetDisplayName();
            var weight = string.Empty;
            var regionRank = 0;
            var regionCount = 0;
            var regionPercentile = -1;

            if (issuePerformance != null)
            {
                score = ScoreConversion.GetRoundedScore(issuePerformance.Score)
                    .ToString(CultureInfo.InvariantCulture);

                assesment = issuePerformance.Assessment.GetDisplayName();

                weight = issuePerformance.Weight.ToString("P0");

                var regionPerformance = issuePerformance.Performances.Where(p => p.PerformanceType == PerformanceType.Region).ToList();
                if (regionPerformance.Count == 1)
                {
                    regionRank = regionPerformance[0].Rank;
                    regionCount = regionPerformance[0].GroupCount;
                    regionPercentile = ScoreConversion.GetRoundedScore(regionPerformance[0].Percentile);
                }
            }


            var width = _report.PageMaxWidth;
            var height = _report.PageMaxHeight - 55f;

            var table = GetDefaultTable(0.0f, 20.0f, width, height);

            table.Columns.Add(width);

            var row = table.Rows.Add(issueTitleHeight);

            var text = string.Format("<p><font color='FFFFFF'><b>{0}</b></font></p>", issue.Name);
            var formattedTextArea = new FormattedTextArea(text, 5f, 1f, width, issueFontSize + 2f,
                Fonts.CalibriFontFamily, issueFontSize, false);

            var cell = row.Cells.Add(formattedTextArea);
            cell.BackgroundColor = Colors.SectionColor;
            cell.VAlign = VAlign.Center;

            row = table.Rows.Add(EmptyRowHeight);
            row.Cells.Add(string.Empty);

            var issueBulletsTable = AddIssueBullets(issue.Name, score, assesment, weight, regionRank, regionCount, regionPercentile, width);
            var rowHeight = issueBulletsTable.GetRequiredHeight();

            row = table.Rows.Add(rowHeight);
            row.Cells.Add(issueBulletsTable);

            row = table.Rows.Add(EmptyRowHeight);
            row.Cells.Add(string.Empty);

            row = table.Rows.Add(issueTitleHeight);
            cell = row.Cells.Add(
                new Label(string.Format("{0} - Indicators", issue.Name), 0.0f, 0.0f, width,
                    issueFontSize + 2f, Fonts.CalibriBold, issueFontSize));
            cell.Border.Bottom.LineStyle = LineStyle.Solid;
            cell.Border.Bottom.Width = 1.5f;
            cell.Border.Bottom.Color = RgbColor.Black;

            row = table.Rows.Add(EmptyRowHeight);
            row.Cells.Add(string.Empty);

            return table;
      


        }
     }
}

